package org.example.service;

import org.example.exception.AppException;
import org.example.exception.ClientException;
import org.example.exception.SystemException;
import org.example.mapper.SettingMapper;
import org.example.mapper.UserMapper;
import org.example.model.Setting;
import org.example.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

@Service
public class UserService {
    @Value("${user.head.local-path}")
    private String localPath; //保存在本地图像

    @Value("${user.head.remote-path}")
    private String remotePath; // 远程访问路径

    @Value("${user.head.filename}")
    private String fileName; // 这个是为了 前两个拼接路经所使用到的

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private SettingMapper settingMapper;

    @Autowired
    private SettingService settingService;

    private static final DateFormat DF = new SimpleDateFormat("yyyyMMdd");

    @Value("${user.head.local-path}")
    private String headLocalPath;

    @Value("${user.head.remote-path}")
    private String headRemotePath;

//    public User login(User user){
//        User query = new User();
//        query.setUsername(user.getUsername());
//        User exist = userMapper.selectByUsername(query);
//        if(exist != null){
//            throw new ClientException("USER001","用户不存在");
//        }
//        if(!exist.getPassword().equals(user.getPassword())){
//            throw new ClientException("USER002","用户名密码校验失败");
//        }
//        return exist;
//    }

    public String saveHead(MultipartFile headFile) {//保存在本地路径：拍脑门决定的路径
        //文件夹为当天：文件路径的间隔符和操作系统相关，可以使用File.separator，但是java也会根据操作系统自行设置
        Date now = new Date();
        String dirUri = "/"+DF.format(now);//20210203
        File dir = new File(headLocalPath+dirUri);
        if(!dir.exists()) dir.mkdirs();
        //保存在本地以天为单位的文件夹，保证文件唯一：随机字符串作为文件名，但是后缀还需要保留
        String suffix = headFile.getOriginalFilename()
                .substring(headFile.getOriginalFilename().lastIndexOf("."));
        String headName = UUID.randomUUID().toString()+suffix;
        String uri = dirUri+"/"+headName;
        try {
            headFile.transferTo(new File(headLocalPath+uri));
        } catch (IOException e) {
            throw new AppException("REG001", "上传用户头像出错");
        }
        return headRemotePath+uri;
    }

    //事务处理：多个更新必须，有部分查询+更新有时候也需要
    //内部实现：aop，方法前加入开启事务逻辑，方法执行后，抛异常rollback，没有异常commit
    //禁止使用try catch吃异常
    @Transactional//可以手动指定隔离级别和传播特性
    public void register(User user) {
        User query = new User();
        query.setUsername(user.getUsername());
        User exist = userMapper.selectByUsername(query.getUsername());
        if(exist != null){
            throw new ClientException("003","用户已存在"); // 根据用户名查询已有的用户信息, 如果存在则不允许注册
        }

        //数据库校验：校验用户名不能重复，省略，自行扩展
        //插入user数据：插入后自增主键会按照useGeneratedKeys=true设置到对象属性
        int n = userMapper.insertSelective(user);

        //插入setting数据：登录后，进入设置页面，添加奖项和抽奖人员，需要setting_id
        Setting setting = new Setting();
        setting.setUserId(user.getId());
        setting.setBatchNumber(8);//每次抽奖的数量：设置一个默认值（业务决定，我们这里拍脑门）
        settingMapper.insertSelective(setting);
    }


    // 默认的事务的配置为 spring 事务的传播特性 = required, 事务的隔离级别为数据库的默认事务隔离级别
    // required 表示当前如果有事务的话 就加入一个事务, 如果没有事务的话就创建一个事务
    @Transactional//
    public void register(User user,MultipartFile headFile)  {

        User query = new User();
        query.setUsername(user.getUsername());
        User exist = userMapper.selectByUsername(query.getUsername());
        if(exist != null){
            throw new ClientException("003","用户已存在"); // 根据用户名查询已有的用户信息, 如果存在则不允许注册
        }

        // 保存注册用户信息 (插入操作)
        String path = "/"+user.getUsername()+"/"+fileName;
        // 保存在本地数据库
        user.setHead(remotePath+path); // 把绝对路径放到数据库
        userMapper.insertSelective(user); // 插入数据, 插入成功之后 自增主键通过 mybatis 的 <selectKey>返回对象

        // 注册用户时 完成初始化操作, 创建 setting 操作
        Setting setting = new Setting();
        setting.setUserId(user.getId());
        setting.setBatchNumber(8); //设置默认抽奖数量
        settingService.add(setting);

        // 保存注册用户头像到本地的文件夹
        FileOutputStream fos = null;
        BufferedOutputStream bos = null;
        try {
            try {
                File dir = new File(localPath+"/"+user.getUsername());
                dir.mkdirs();
                fos = new FileOutputStream(localPath+path);// 接下来输出到本地的一个文件里面
                bos = new BufferedOutputStream(fos); // 缓存的输出流
                bos.write(headFile.getBytes()); // 获取二进制数组
                bos.flush(); //刷新一下
            } finally {
                if(bos != null)
                    bos.close();
                if (fos!=null)
                    fos.close();
            }
        } catch (IOException e) {
            // 打印捕获的异常, 抛出自定义异常, 统一异常拦截器, 进行打印自定义异常
//            e.printStackTrace();
//            throw new SystemException("USR004","用户注册失败: 上传头像出错");
            throw new SystemException("USR004","用户注册失败: 上传头像出错",e);
        }
    }

    public User queryByUsername(String username) {

        return userMapper.selectByUsername(username);
    }
}
